﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

namespace ibba.src.noriskbo
{
    public class ValidatorFields: INotifyDataErrorInfo
    {
        #region Classes Auxiliares

        public enum ConditionType
        {
            GreaterThan,
            LessThan,
            MinimumChar
        }
        public class AdditionalValidation
        {
            public object Value { get; set; }
            public ConditionType Condition { get; set; }
            public string MsgError { get; set; }
        }
        public class Field
        {
            public string Name { get; set; }
            public string MsgError { get; set; }
            public AdditionalValidation AdditionalValidator { get; set; }
        }

        #endregion
        
        #region INotifyDataErrorInfo Members

        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

        public IEnumerable GetErrors(string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName))
            {
                return (_errors.Values);
            }

            string message = null;
            _errors.TryGetValue(propertyName, out message);

            return message;
        }

        public bool HasErrors
        {
            get { return _errors.Count > 0; }
        }

        #endregion

        protected readonly Dictionary<string, string> _errors;
        
        public ValidatorFields()
        {
            _errors = new Dictionary<string, string>();
            this.Fields = new List<Field>();
        }

        public List<Field> Fields { get; set; }
       
        public void AddValidation(string pField)
        {
            AddValidation(pField, null, null);
        }        
        public void AddValidation(string pField, AdditionalValidation pAdditionalValidator)
        {
            AddValidation(pField, null, pAdditionalValidator);
        }
        //public void AddValidation(string pField, string pMsgErrorOpcional)
        //{
        //    AddValidation(pField, pMsgErrorOpcional, null);
        //}
        public void AddValidation(string pField, string pMsgErrorOpcional, AdditionalValidation pAdditionalValidator)
        {
            Fields.Add(new Field { Name = pField, MsgError = pMsgErrorOpcional, AdditionalValidator = pAdditionalValidator });
        }

        public string Validate(object pEntity, string pField)
        {
            string msg = null;

            Field cmp = Fields.SingleOrDefault(c => c.Name == pField);

            if (cmp != null)
            {
                string value = System.Convert.ToString(pEntity.GetType().GetProperty(cmp.Name).GetValue(pEntity, null));

                if (string.IsNullOrWhiteSpace(value))
                {
                    msg = string.IsNullOrWhiteSpace(cmp.MsgError) ? "Campo de preenchimento obrigatório" : cmp.MsgError;
                }
                else
                {
                    double dbl = 0;
                    DateTime dt = new DateTime();

                    if (cmp.AdditionalValidator != null)
                    {
                        switch (cmp.AdditionalValidator.Condition)
                        {
                            case ConditionType.GreaterThan:
                                if (double.TryParse(value, out dbl))
                                {
                                    if (dbl <= double.Parse(cmp.AdditionalValidator.Value.ToString()))
                                        msg = string.Concat("Valor deve ser maior que ", cmp.AdditionalValidator.Value.ToString());
                                }
                                else if (DateTime.TryParse(value, out dt))
                                { 
                                    if (dt <= DateTime.Parse(cmp.AdditionalValidator.Value.ToString()))
                                        msg = string.Concat("Informe uma data maior que ", DateTime.Parse(cmp.AdditionalValidator.Value.ToString()).ToShortDateString());
                                }

                                break;
                            case ConditionType.LessThan:
                                if (double.TryParse(value, out dbl))
                                {
                                    if (dbl >= double.Parse(cmp.AdditionalValidator.Value.ToString()))
                                        msg = string.Concat("Valor deve ser menor que ", cmp.AdditionalValidator.Value.ToString());
                                }
                                else if (DateTime.TryParse(value, out dt))
                                { 
                                    if (dt >= DateTime.Parse(cmp.AdditionalValidator.Value.ToString()))
                                        msg = string.Concat("Informe uma data menor que ", DateTime.Parse(cmp.AdditionalValidator.Value.ToString()).ToShortDateString());
                                }
                                break;

                            case ConditionType.MinimumChar:
                                if (value.Length < int.Parse(cmp.AdditionalValidator.Value.ToString()))
                                    msg = string.Format("Valor deve ser preenchido com no mínimo {0} caracteres.", cmp.AdditionalValidator.Value.ToString());

                                break;
                        }

                        //Verifica se tem mensagem de erro definida para retornar
                        if (!string.IsNullOrEmpty(msg))
                            msg = string.IsNullOrEmpty(cmp.AdditionalValidator.MsgError) ? msg : cmp.AdditionalValidator.MsgError;
                    }
                }
            }

            RemoveError(pField);

            if (!string.IsNullOrEmpty(msg))
                AddError(pField, msg);

            return msg;
        }
        
        #region PrivateMethod

        private void AddError(string propertyName, string message)
        {
            if (!_errors.ContainsKey(propertyName))
                _errors[propertyName] = message;

            FireErrorsChanged(propertyName);
        }

        private void RemoveError(string propertyName)
        {
            _errors.Remove(propertyName);

            FireErrorsChanged(propertyName);
        }

        private void FireErrorsChanged(string property)
        {
            if (ErrorsChanged != null)
                ErrorsChanged(this, new DataErrorsChangedEventArgs(property));
        } 

        #endregion
    }
       
}
